package com.culture.bootdemo.utils;

import org.apache.commons.codec.binary.Base64;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;

/**
 * @author wen
 * @date 2020/8/18 17:28
 * @Description rsa非对称加密
 **/
public class RSAEncryUtil {

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    public static final String KEY_ALGORITHM = "RSA";
    private static KeyFactory keyFactory = null;

    public final static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaqDmw4BzZuyXDH1OOiwIJ3m4Nizu89Oul9ink5dmgwXm3oaknOulbKyelCatJgkAtljTYqtgmN/bg/K1GR0aEbprkObD8Z/bfyuESbp6G24yYHxntn8y0ysPZ1hnBSm1JS/v8l5dqWFLbRYYf5xYiFtTtwA0m4MQiHJEAOabdeQIDAQAB";
    public final static String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJqoObDgHNm7JcMfU46LAgnebg2LO7z066X2KeTl2aDBebehqSc66VsrJ6UJq0mCQC2WNNiq2CY39uD8rUZHRoRumuQ5sPxn9t/K4RJunobbjJgfGe2fzLTKw9nWGcFKbUlL+/yXl2pYUttFhh/nFiIW1O3ADSbgxCIckQA5pt15AgMBAAECgYBJ/2WjEIgdUWMPCiUTlcVC7Y8godbSYSmC/dYrtCI9vXS8fPgPUiunOG2+lHLFODH23eCpLo0/NBXGrn9FmgLNyQ8OVNZplPzbzYdQRARht6UUCsxaLAVhpbnajbCzGNKNstIZDIGd2w+f8U42oI0HN68rj4RKtpn6hFVEgOOsAQJBAN2QsPhzsMZ0eOEcz6RZ6MGC4CDxUalIqRogSwIuTbtx0FHpfZL41yNPdkD47Q+2gtvpx5GJP4rP1MYrXSuLbIECQQCysX6iZMgQY84L4AU0vP2ONslsjsyA2d5rYypySKl8Z19c+SGsbyOTFWmhi34sQgd6rTTfEnZc0IrofpAncFT5AkBAmKWv2fLo+R4g64hyLzBX8rMrh4+6Xg/HKTEVMrDA/H6y0vMkfV4j0k/0w15CHYDrYq4ndS9MZilvmUbxohWBAkEAnpAV2LApPzHw4mS0+elB7XH8JlJIcYXicdQbFDIaAwQPgQaotMQiAyAbDXgkS82DqX4Mzm0pjo6W1FuKOxTYsQJAWdst67yxQgbhJRVIdESymxvhfMZ6rBQC6sP5RkPKPK6UdPJ7/KkRGK4+qme+i9OYoo3CijIZodIPNZm7SO6JfQ==";


    static {
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }


    public static Key getPrivateKeyFromBase64KeyEncodeStr(String keyStr) {
        byte[] keyBytes = Base64.decodeBase64(keyStr);
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        Key privateKey = null;
        try {
            privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return privateKey;
    }

    /**
     * 获取base64加密后的字符串的原始公钥
     *
     * @param keyStr
     * @return
     */
    public static Key getPublicKeyFromBase64KeyEncodeStr(String keyStr) {
        byte[] keyBytes = Base64.decodeBase64(keyStr);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        Key publicKey = null;
        try {
            publicKey = keyFactory.generatePublic(x509KeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    /**
     * 使用公钥进行分段加密
     *
     * @param dataStr 要加密的数据
     * @return 公钥base64字符串
     * @throws Exception
     */
    public static String encryptByPublicKey(String dataStr)
            throws Exception {
        //要加密的数据
        System.out.println("要加密的数据:" + dataStr);
        byte[] data = dataStr.getBytes();
        // 对公钥解密
        Key decodePublicKey = getPublicKeyFromBase64KeyEncodeStr(PUBLIC_KEY);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, decodePublicKey);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        String encodedDataStr = Base64.encodeBase64String(encryptedData);
        System.out.println("公钥加密后的数据:" + encodedDataStr);
        return encodedDataStr;
    }

    /**
     * 使用私钥进行分段解密
     *
     * @param dataStr 使用base64处理过的密文
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decryptByPrivateKey(String dataStr)
            throws Exception {

        byte[] encryptedData = Base64.decodeBase64(dataStr);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key decodePrivateKey = getPrivateKeyFromBase64KeyEncodeStr(PRIVATE_KEY);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, decodePrivateKey);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        String decodedDataStr = new String(decryptedData, StandardCharsets.UTF_8);
        System.out.println("私钥解密后的数据:" + decodedDataStr);
        return decodedDataStr;
    }

    public static void main(String[] args) throws Exception {
//        String str = "你好吗这是这是";
        String str = "{\"companyName\":\"\",\"creditCardNumber\":\"\",\"dataUniqueId\":\"\",\"debtTotal\":1252.21,\"debtorIdCard\":\"\",\"debtorName\":\"魏秋艺\",\"debtorPhone\":\"13296390487\",\"debtorSex\":0,\"duration\":\"82\",\"endTime\":\"2020-08-18 10:41:38\",\"filePath\":\"http://bucket-voice-staging.oss-cn-zhangjiakou.aliyuncs.com/freeswitch/2020-08-18/13296390487-1deaa9f2-e0fc-11ea-a241-23f555ebe40f.wav?Expires=1597737670&OSSAccessKeyId=LTAI8O70NhYgl7IE&Signature=8YR9/WYQU93YBa3J9/tCwGe2XeU%3D\",\"intentionLabel\":\"已经还款\",\"overdueDay\":1,\"productName\":\"\",\"remark\":\"[{\\\"output\\\":\\\"您好，我是至尊借款的催收专员, 请问是刘振栋先生吗？\\\",\\\"input\\\":\\\"喂\\\",\\\"node_name\\\":\\\"身份确认\\\"}, {\\\"output\\\":\\\"您好，您在至尊借款有一笔387.59的借款，已经逾期3天了，您今天几点能处理好这笔款项呢？\\\",\\\"input\\\":\\\"好，可以可以可以\\\",\\\"node_name\\\":\\\"协商还款\\\"}, {\\\"output\\\":\\\"大概几点呢，请给我一个准确的时间点好吗？我们需要帮您在系统备案。\\\",\\\"input\\\":\\\"\\\",\\\"node_name\\\":\\\"几点还款\\\"}, {\\\"output\\\":\\\"请给我一个准确的时间点好吗？我们需要帮您在系统备案。\\\",\\\"input\\\":\\\"\\\",\\\"node_name\\\":\\\"几点还款\\\"}, {\\\"output\\\":\\\"请给我一个准确的时间点好吗？我们需要帮您在系统备案。\\\",\\\"input\\\":\\\"点6点\\\",\\\"node_name\\\":\\\"几点还款\\\"}, {\\\"output\\\":\\\"好的，请遵守承诺按时还款，如果系统没有收到还款，我们会再次联系你，请保持电话畅通，避免案件升级，再见。最后，如果您有什么问题意见建议等，可以告诉我，我帮您记录下来。没有请直接挂机。\\\",\\\"input\\\":\\\"\\\",\\\"node_name\\\":\\\"结束语1\\\"}]\",\"startTime\":\"2020-08-18 10:40:02\",\"status\":\"接通\",\"toolType\":\"联络机器人\"}";
        String s = encryptByPublicKey(str);
       /* System.out.println(s);
        System.out.println("=========");*/
        System.out.println(decryptByPrivateKey(s));

    }
}
